home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / vm / sun3.md / vmSunAsm.s < prev    next >
Text File  |  1991-03-21  |  24KB  |  877 lines

  1.  
  2. |* vmSun.s -
  3. |*
  4. |*    Subroutines to access Sun virtual memory mapping hardware.
  5. |*    All of the routines in here assume that source and destination
  6. |*    function codes are set to MMU space.
  7. |*
  8. |* Copyright (C) 1985 Regents of the University of California
  9. |* All rights reserved.
  10. |*
  11.  
  12. #include "vmSunConst.h"
  13. #include "machAsmDefs.h"
  14.  
  15.     .data
  16.     .asciz "$Header: /sprite/src/kernel/vm/sun3.md/RCS/vmSunAsm.s,v 1.4 90/09/11 10:46:20 shirriff Exp $ SPRITE (Berkeley)"
  17.     .even
  18.     .text
  19.  
  20.  
  21. |*
  22. |* ----------------------------------------------------------------------------
  23. |*
  24. |* VmMachReadPTE --
  25. |*
  26. |*         Map the given hardware pmeg into the kernel's address space and 
  27. |*    return the pte at the corresponding address.  There is a reserved
  28. |*    address in the kernel that is used to map this hardware pmeg.
  29. |*
  30. |*    VmMachPTE VmMachReadPTE(pmegNum, addr)
  31. |*        int        pmegNum;/* The pmeg to read the PTE for. */
  32. |*        Address    addr;    /* The virtual address to read the PTE for. */
  33. |*
  34. |* Results:
  35. |*     The value of the PTE.
  36. |*
  37. |* Side effects:
  38. |*     None.
  39. |*
  40. |* ----------------------------------------------------------------------------
  41. |*
  42.     .globl    _VmMachReadPTE
  43. _VmMachReadPTE:
  44. |* 
  45. |* Set the segment map entry.
  46. |*
  47.     movl    _vmMachPTESegAddr,a0    | Get access address
  48.     addl    #VMMACH_SEG_MAP_OFF,a0    | Bump to segment map offset
  49.     movl    sp@(4),d0        | Get segment map entry to write.
  50.     movsb    d0,a0@            | Write segment map entry
  51.  
  52. |*
  53. |* Get the page map entry.
  54. |*
  55.     movl    sp@(8),d0        | Get virtual address
  56.     andw    #VMMACH_PAGE_MAP_MASK,d0| Mask out low bits
  57.     addl    #VMMACH_PAGE_MAP_OFF,d0    | Add in page map offset.
  58.     movl    d0, a0
  59.     movsl    a0@,d0            | d0 <= page map entry
  60.  
  61.     rts                    | Return
  62.  
  63.  
  64. |*
  65. |* ----------------------------------------------------------------------------
  66. |*
  67. |* VmMachWritePTE --
  68. |*
  69. |*         Map the given hardware pmeg into the kernel's address space and 
  70. |*    write the pte at the corresponding address.  There is a reserved
  71. |*    address in the kernel that is used to map this hardware pmeg.
  72. |*
  73. |*    void VmMachWritePTE(pmegNum, addr, pte)
  74. |*        int           pmegNum;    /* The pmeg to write the PTE for. */
  75. |*        Address    addr;        /* The address to write the PTE for. */
  76. |*        VmMachPTE    pte;        /* The page table entry to write. */
  77. |*
  78. |* Results:
  79. |*     None.
  80. |*
  81. |* Side effects:
  82. |*     The hardware page table entry is set.
  83. |*
  84. |* ----------------------------------------------------------------------------
  85. |*
  86.     .globl    _VmMachWritePTE
  87. _VmMachWritePTE:
  88. |* 
  89. |* Set the segment map entry.
  90. |*
  91.     movl    _vmMachPTESegAddr,a0    | Get access address
  92.     addl    #VMMACH_SEG_MAP_OFF,a0    | Bump to segment map offset
  93.     movl    sp@(4),d0        | Get segment map entry to write.
  94.     movsb    d0,a0@            | Write segment map entry
  95.  
  96. |*
  97. |* Set the page map entry.
  98. |*
  99.     movl    sp@(8),d0        | Get virtual address into a register
  100.     andw    #VMMACH_PAGE_MAP_MASK,d0    | Mask out low bits
  101.     addl    #VMMACH_PAGE_MAP_OFF,d0    | Add in page map offset.
  102.     movl    d0, a0
  103.     movl    sp@(12),d0        | Get page map entry into a register
  104.     movsl    d0,a0@            | Write page map entry
  105.  
  106.     rts                    | Return
  107.  
  108. |*
  109. |* ----------------------------------------------------------------------------
  110. |*
  111. |* VmMachGetPageMap --
  112. |*
  113. |*         Return the page map entry for the given virtual address.
  114. |*    It is assumed that the user context register is set to the context
  115. |*    for which the page map entry is to retrieved.
  116. |*
  117. |*    int Vm_GetPageMap(virtualAddress)
  118. |*        Address virtualAddress;
  119. |*
  120. |* Results:
  121. |*     The contents of the hardware page map entry.
  122. |*
  123. |* Side effects:
  124. |*     None.
  125. |*
  126. |* ----------------------------------------------------------------------------
  127. |*
  128.     .globl    _VmMachGetPageMap
  129. _VmMachGetPageMap:
  130.     movl    sp@(4),d0        | Get virtual address into a register
  131.     andw    #VMMACH_PAGE_MAP_MASK,d0| Get relevant bits from address.
  132.     addl    #VMMACH_PAGE_MAP_OFF,d0    | Add in page map offset.
  133.     movl    d0, a0
  134.     movsl    a0@,d0            | Read page map entry
  135.  
  136.     rts                    | Return
  137.  
  138. |*
  139. |* ----------------------------------------------------------------------------
  140. |*
  141. |* VmMachGetSegMap --
  142. |*
  143. |*         Return the segment map entry for the given virtual address.
  144. |*    It is assumed that the user context register is set to the context
  145. |*    for which the segment map entry is to retrieved.
  146. |*
  147. |*    int VmMachGetSegMap(virtualAddress)
  148. |*        Address virtualAddress;
  149. |*
  150. |* Results:
  151. |*     The contents of the segment map entry.
  152. |*
  153. |* Side effects:
  154. |*     None.
  155. |*
  156. |* ----------------------------------------------------------------------------
  157. |*
  158.     .globl    _VmMachGetSegMap
  159. _VmMachGetSegMap:
  160.     movl    sp@(4),d0        | Get virtual address in a register.
  161.     andw    #VMMACH_SEG_MAP_MASK,d0    | Get relevant bits.
  162.     addl    #VMMACH_SEG_MAP_OFF,d0    | Add in segment map offset
  163.     movl    d0, a0
  164.     clrl    d0            | Clear the return register.
  165.     movsb    a0@,d0            | Read segment map entry into return
  166.                     | register.
  167.  
  168.     rts                    | Return
  169.  
  170. |*
  171. |* ----------------------------------------------------------------------------
  172. |*
  173. |* VmMachSetPageMap --
  174. |*
  175. |*         Set the page map entry for the given virtual address to the pte valud 
  176. |*      given in pte.  It is assumed that the user context register is 
  177. |*    set to the context for which the page map entry is to be set.
  178. |*
  179. |*    void VmMachSetPageMap(virtualAddress, pte)
  180. |*        Address     virtualAddress;
  181. |*        VmMachPTE    pte;
  182. |*
  183. |* Results:
  184. |*     None.
  185. |*
  186. |* Side effects:
  187. |*     The hardware page map entry is set.
  188. |*
  189. |* ----------------------------------------------------------------------------
  190. |*
  191.     .globl    _VmMachSetPageMap
  192. _VmMachSetPageMap:
  193.     movl    sp@(4),d0        | Get virtual address into a register
  194.     andw    #VMMACH_PAGE_MAP_MASK,d0| Mask out low bits
  195.     addl    #VMMACH_PAGE_MAP_OFF,d0    | Add in page map offset.
  196.     movl    d0, a0
  197.     movl    sp@(8),d0        | Get page map entry into a register
  198.     movsl    d0,a0@            | Write page map entry
  199.  
  200.     rts                    | Return
  201.  
  202. |*
  203. |* ----------------------------------------------------------------------------
  204. |*
  205. |* VmMachPMEGZero --
  206. |*
  207. |*         Set all of the page table entries in the pmeg to 0.  There is a special
  208. |*    address in the kernel's address space (vmMachPTESegAddr) that is used to
  209. |*    map the pmeg in so that it can be zeroed.
  210. |*
  211. |*    void VmMachPMEGZero(pmeg)
  212. |*        int pmeg;
  213. |*
  214. |* Results:
  215. |*     None.
  216. |*
  217. |* Side effects:
  218. |*     The given pmeg is zeroed.
  219. |*
  220. |* ----------------------------------------------------------------------------
  221. |*
  222.  
  223.     .globl    _VmMachPMEGZero
  224. _VmMachPMEGZero:
  225. | Write segment map entry
  226.     movl    _vmMachPMEGSegAddr, d1    
  227.     movl    d1, a0            
  228.     addl    #VMMACH_SEG_MAP_OFF, a0    | a0 <= Segment map address    
  229.     movl    sp@(4),d0        | d0 <= PMEG num
  230.     movsb    d0,a0@            | Write PMEG num to segment map
  231.  
  232. | Now zero out all page table entries.
  233.  
  234.     movl    d1, a0            | a0 <= Starting address
  235.     addl    #VMMACH_PAGE_MAP_OFF, a0
  236.                     | d1 <= Ending address
  237.     addl    #(VMMACH_SEG_SIZE + VMMACH_PAGE_MAP_OFF), d1    
  238.     clrl    d0            | Clear out d0.
  239. 1:
  240.     movsl    d0,a0@            | Write page map entry
  241.     addl    #VMMACH_PAGE_SIZE_INT, a0 | Go to next address.
  242.     cmpl    a0, d1            | See if have initialized all 
  243.     bgt        1b            |     ptes.
  244.  
  245.     rts                    | Return
  246.  
  247. |*
  248. |* ----------------------------------------------------------------------------
  249. |*
  250. |* VmMachReadAndZeroPMEG --
  251. |*
  252. |*    Read out all page table entries in the given pmeg and then set each to
  253. |*    zero. There is a special address in the kernel's address space 
  254. |*    (vmMachPTESegAddr) that is used to access the PMEG.
  255. |*
  256. |*    void VmMachPMEGZero(pmeg, pteArray)
  257. |*        int     pmeg;
  258. |*        VmMachPTE    pteArray[VMMACH_NUM_PAGES_PER_SEG];
  259. |*
  260. |* Results:
  261. |*      None.
  262. |*
  263. |* Side effects:
  264. |*     The given pmeg is zeroed and *pteArray is filled in with the contents
  265. |*    of the PMEG before it is zeroed.
  266. |*
  267. |* ----------------------------------------------------------------------------
  268. |*
  269.  
  270.     .globl    _VmMachReadAndZeroPMEG
  271. _VmMachReadAndZeroPMEG:
  272.     movl    _vmMachPMEGSegAddr, a0
  273.     addl    #VMMACH_SEG_MAP_OFF, a0        | a0 <= Segment map address    
  274.     movl    sp@(4),d0            | d0 <= PMEG num
  275.     movsb    d0,a0@                | Write PMEG num to segment map
  276.     movl    sp@(8), a1            | a1 <= pteArray
  277. | Subtract off seg map offset and add page map offset into a0.
  278.     addl    #(VMMACH_PAGE_MAP_OFF - VMMACH_SEG_MAP_OFF), a0
  279.     movl    #VMMACH_NUM_PAGES_PER_SEG_INT, d1    | d1 <= Pmegs per seg.
  280. 1:
  281.     movsl    a0@, d0                | Read out the pte
  282.     movl    d0, a1@+            | a1 <= the pte
  283.     clrl    d0
  284.     movsl    d0, a0@                | Clear out the pte.
  285.     addl    #VMMACH_PAGE_SIZE_INT, a0    | Go to next address.
  286.     subql    #1, d1
  287.     bgt        1b            
  288.  
  289.     rts            
  290.  
  291.  
  292. |*
  293. |* ----------------------------------------------------------------------------
  294. |*
  295. |* VmMachTracePMEG --
  296. |*
  297. |*    Read out all page table entries in the given pmeg, generate trace
  298. |*    records for each with ref or mod bit set and then clear the ref
  299. |*    and mod bits.
  300. |*
  301. |*    void VmMachTracePMEG(pmeg)
  302. |*
  303. |* Results:
  304. |*      None.
  305. |*
  306. |* Side effects:
  307. |*    The reference and modified bits are cleared for all pages in
  308. |*    this PMEG.
  309. |*
  310. |* ----------------------------------------------------------------------------
  311. |*
  312.  
  313. #define    PTE_MASK (VMMACH_RESIDENT_BIT + VMMACH_REFERENCED_BIT + VMMACH_MODIFIED_BIT)
  314.  
  315.     .globl    _VmMachTracePMEG
  316. _VmMachTracePMEG:
  317.     movl    sp@(4), d0            | d0 <= PMEG num
  318.     moveml    #0x3020, sp@-            | Save d2, d3 and a2
  319.  
  320.     movl    _vmMachPMEGSegAddr, a2
  321.     addl    #VMMACH_SEG_MAP_OFF, a2        | a2 <= Segment map address    
  322.     movsb    d0,a2@                | Write PMEG num to segment map
  323. | Subtract off seg map offset and add page map offset into a2.
  324.     addl    #(VMMACH_PAGE_MAP_OFF - VMMACH_SEG_MAP_OFF), a2
  325.     movl    #VMMACH_NUM_PAGES_PER_SEG_INT, d3    | d3 <= Pmegs per seg.
  326. 1:
  327.     movsl    a2@, d2                | Read out the pte
  328.  
  329. |*
  330. |* Trace this page if it is resident and the reference and modify bits
  331. |* are set.
  332. |*
  333.  
  334.     movl    d2, d0
  335.     andl    #PTE_MASK, d0
  336.     beq        2f
  337.     cmpl    #VMMACH_RESIDENT_BIT, d0
  338.     beq        2f
  339.     movl    d3, sp@-            | Push page num onto stack.
  340.     movl    d2, sp@-            | Push pte onto stack.
  341.                         | Clear the ref and mod bits.
  342.     andl    #(~(VMMACH_REFERENCED_BIT + VMMACH_MODIFIED_BIT)), d2
  343.     movsl    d2, a2@
  344.     jsr        _VmMachTracePage        | VmMachTrace(pte, pageNum)
  345.     addql    #8, sp
  346.  
  347. 2:
  348. |* 
  349. |* Go to the next page.
  350. |*
  351.     addl    #VMMACH_PAGE_SIZE_INT, a2    | Go to next address.
  352.     subql    #1, d3
  353.     bgt        1b            
  354.  
  355.     moveml    sp@+, #0x040c            | Restore a2, d3 and d2
  356.  
  357.     rts            
  358.  
  359. |*
  360. |* ----------------------------------------------------------------------------
  361. |*
  362. |* VmMachSetSegMap --
  363. |*
  364. |*         Set the segment map entry for the given virtual address to the given 
  365. |*    value.  It is assumed that the user context register is set to the 
  366. |*    context for which the segment map entry is to be set.
  367. |*
  368. |*    void VmMachSetSegMap(virtualAddress, value)
  369. |*        Address        virtualAddress;
  370. |*        unsigned char    value;
  371. |*
  372. |* Results:
  373. |*     None.
  374. |*
  375. |* Side effects:
  376. |*     Hardware segment map entry for the current user context is set.
  377. |*
  378. |* ----------------------------------------------------------------------------
  379. |*
  380.     .globl    _VmMachSetSegMap
  381. _VmMachSetSegMap:
  382.     movl    sp@(4),d0        | Get access address
  383.     andw    #VMMACH_SEG_MAP_MASK,d0    | Mask out low bits
  384.     addl    #VMMACH_SEG_MAP_OFF,d0    | Bump to segment map offset
  385.     movl    d0, a0
  386.     movl    sp@(8),d0        | Get segment map entry to write in a 
  387.                         | register.
  388.     movsb    d0,a0@            | Write segment map entry
  389.  
  390.     rts                        | return
  391.  
  392. |*
  393. |* ----------------------------------------------------------------------------
  394. |*
  395. |* VmMachSegMapCopy --
  396. |*
  397. |*         Copy the software segment map entries into the hardware segment entries.
  398. |*    All segment table entries between address startAddr and address
  399. |*    endAddr are copied.  It is assumed that the user context register is 
  400. |*    set to the context for which the segment map entries are to be set.
  401. |*    
  402. |*    void VmMachSegMapCopy(tablePtr, startAddr, endAddr)
  403. |*        char *tablePtr;
  404. |*        int startAddr;
  405. |*        int endAddr;
  406. |*
  407. |* Results:
  408. |*     None.
  409. |*
  410. |* Side effects:
  411. |*     Hardware segment map entries for the current user context are set.
  412. |*
  413. |* ----------------------------------------------------------------------------
  414. |*
  415.     .globl _VmMachSegMapCopy
  416. _VmMachSegMapCopy:
  417.     movl    sp@(4),a0        | Get segment table address
  418.     movl    sp@(8),d1        | Get start address in a register.
  419.     andw    #VMMACH_SEG_MAP_MASK,d1    | Mask out low bits
  420.     addl    #VMMACH_SEG_MAP_OFF,d1    | Bump to segment map offset
  421.     movl    d1, a1
  422.     movl    sp@(12),d1        | Get end address in a register.
  423.     addl    #VMMACH_SEG_MAP_OFF, d1    | Add in offset.
  424. 1:
  425.     movb    a0@,d0            | Get segment map entry to write.
  426.     movsb    d0,a1@            | Write segment map entry
  427.     addql    #1, a0            | Increment the address to copy from.
  428.     addl    #VMMACH_SEG_SIZE, a1    | Increment the address to copy to.
  429.     cmpl    a1, d1            | See if hit upper bound.  If not     
  430.     bgt        1b            | continue.
  431.  
  432.     rts
  433. /*
  434.  * Sun 2's require that the context offset be treated as a word and on Sun-3's
  435.  * it can't be.
  436.  */
  437.  
  438. #ifdef sun3
  439. #define    VMMACH_UC_OFF VMMACH_CONTEXT_OFF
  440. #define    VMMACH_KC_OFF VMMACH_CONTEXT_OFF
  441. #else
  442. #define    VMMACH_UC_OFF VMMACH_USER_CONTEXT_OFF:w
  443. #define    VMMACH_KC_OFF VMMACH_KERN_CONTEXT_OFF:w
  444. #endif
  445.  
  446. |*
  447. |* ----------------------------------------------------------------------------
  448. |*
  449. |* VmMachGetContextReg --
  450. |*
  451. |*         Return the value of the context register (on a Sun-2 the user context
  452. |*    register).
  453. |*
  454. |*    int VmMachGetContextReg()
  455. |*
  456. |* Results:
  457. |*     The value of context register.
  458. |*
  459. |* Side effects:
  460. |*     None.
  461. |*
  462. |* ----------------------------------------------------------------------------
  463. |*
  464.  
  465.     .globl    _VmMachGetContextReg
  466. _VmMachGetContextReg:
  467.                         | Move context reg into result 
  468.                             | register.
  469. #ifdef sun3
  470.     movsb    VMMACH_CONTEXT_OFF,d0         
  471. #else
  472.     movsb    VMMACH_USER_CONTEXT_OFF:w,d0
  473. #endif
  474.     andb    #VMMACH_CONTEXT_MASK,d0        | Clear high-order bits
  475.  
  476.     rts                        | Return
  477.  
  478. |*
  479. |* ----------------------------------------------------------------------------
  480. |*
  481. |* VmMachSetContextReg --
  482. |*
  483. |*         Set the user and kernel context registers to the given value.
  484. |*
  485. |*    void VmMachSetContext(value)
  486. |*        int value;        /* Value to set register to */
  487. |*
  488. |* Results:
  489. |*     None.
  490. |*
  491. |* Side effects:
  492. |*     None.
  493. |*
  494. |* ----------------------------------------------------------------------------
  495. |*
  496.     .globl    _VmMachSetContextReg
  497. _VmMachSetContextReg:
  498.  
  499.     movl    sp@(4),d0            | Get context value to set 
  500.                             | into a 
  501.                             | register
  502.  
  503.                         | Set context register(s).
  504. #ifdef sun3
  505.     movsb    d0, VMMACH_CONTEXT_OFF
  506. #else 
  507.     movsb    d0,VMMACH_USER_CONTEXT_OFF:w 
  508.     movsb    d0,VMMACH_KERN_CONTEXT_OFF:w
  509. #endif
  510.  
  511.     rts                        | Return
  512.  
  513. |*
  514. |* ----------------------------------------------------------------------------
  515. |*
  516. |* VmMachGetUserContext --
  517. |*
  518. |*         Return the value of the user context register.
  519. |*
  520. |*    int VmMachGetUserContext()
  521. |*
  522. |* Results:
  523. |*     The value of user context register.
  524. |*
  525. |* Side effects:
  526. |*     None.
  527. |*
  528. |* ----------------------------------------------------------------------------
  529. |*
  530.     .globl    _VmMachGetUserContext
  531. _VmMachGetUserContext:
  532.     movsb    VMMACH_UC_OFF,d0         | Get context reg value
  533.     andb    #VMMACH_CONTEXT_MASK,d0        | Clear high-order bits
  534.     rts                        | Return
  535.  
  536. |*
  537. |* ----------------------------------------------------------------------------
  538. |*
  539. |* VmMachGetKernelContext --
  540. |*
  541. |*         Return the value of the kernel context register.
  542. |*
  543. |*    int VmMachGetKernelContext()
  544. |*
  545. |* Results:
  546. |*     The value of kernel context register.
  547. |*
  548. |* Side effects:
  549. |*     None.
  550. |*
  551. |* ----------------------------------------------------------------------------
  552. |*
  553.     .globl    _VmMachGetKernelContext
  554. _VmMachGetKernelContext:
  555.     movsb    VMMACH_KC_OFF,d0         | Get context reg value.
  556.     andb    #VMMACH_CONTEXT_MASK,d0        | Clear high-order bits
  557.     rts
  558.  
  559. |*
  560. |* ----------------------------------------------------------------------------
  561. |*
  562. |* VmMachSetUserContext --
  563. |*
  564. |*         Set the user context register to the given value.
  565. |*
  566. |*    void VmMachSetUserContext(value)
  567. |*        int value;        /* Value to set register to */
  568. |*
  569. |* Results:
  570. |*     None.
  571. |*
  572. |* Side effects:
  573. |*     None.
  574. |*
  575. |* ----------------------------------------------------------------------------
  576. |*
  577.  
  578.     .globl    _VmMachSetUserContext
  579. _VmMachSetUserContext:
  580.     movl    sp@(4),d0            | Get context value to set.
  581.     movsb    d0,VMMACH_UC_OFF         | Set context register.
  582.     rts                        | Return
  583.  
  584. |*
  585. |* ----------------------------------------------------------------------------
  586. |*
  587. |* VmMachSetKernelContext --
  588. |*
  589. |*         Set the kernel context register to the given value.
  590. |*
  591. |*    void VmMachSetKernelContext(value)
  592. |*        int value;        /* Value to set register to */
  593. |*
  594. |* Results:
  595. |*     None.
  596. |*
  597. |* Side effects:
  598. |*     The supervisor context is set.
  599. |*
  600. |* ----------------------------------------------------------------------------
  601. |*
  602.  
  603.     .globl    _VmMachSetKernelContext
  604. _VmMachSetKernelContext:
  605.     movl    sp@(4),d0            | Get context value to set
  606.     movsb    d0,VMMACH_KC_OFF         | Set context register
  607.     rts                     | Return
  608.  
  609.  
  610. |*
  611. |* ----------------------------------------------------------------------
  612. |*
  613. |* Vm_Copy{In,Out}
  614. |*
  615. |*    Copy numBytes from *sourcePtr in to *destPtr.
  616. |*    This routine is optimized to do transfers when sourcePtr and 
  617. |*    destPtr are both 4-byte aligned.
  618. |*
  619. |*    void
  620. |*    Vm_Copy{In,Out}(numBytes, sourcePtr, destPtr)
  621. |*        register int numBytes;      /* The number of bytes to copy */
  622. |*        Address sourcePtr;          /* Where to copy from. */
  623. |*        Address destPtr;            /* Where to copy to. */
  624. |*
  625. |*    NOTE: The trap handler assumes that this routine does not push anything
  626. |*          onto the stack.  It uses this fact to allow it to return to the
  627. |*          caller of this routine upon an address fault.  If you must push
  628. |*          something onto the stack then you had better go and modify 
  629. |*          "CallTrapHandler" in asmDefs.h appropriately.
  630. |*
  631. |* Results:
  632. |*    Returns SUCCESS if the copy went OK (which is almost always).  If
  633. |*    a bus error (other than a page fault) occurred while reading or
  634. |*    writing user memory, then SYS_ARG_NO_ACCESS is returned (this return
  635. |*    occurs from the trap handler, rather than from this procedure).
  636. |*
  637. |* Side effects:
  638. |*    The area that destPtr points to is modified.
  639. |*
  640. |* ----------------------------------------------------------------------
  641. |*
  642.     .globl _VmMachDoCopy
  643.     .globl _Vm_CopyIn
  644. _VmMachDoCopy:
  645. _Vm_CopyIn:
  646.     movl    sp@(4),d1            | Get number of bytes into a
  647.                         |     register.
  648.     movl        sp@(8),a0            | Get source and dest addresses
  649.     movl        sp@(12),a1            |     into a register.
  650.  
  651. |*
  652. |* If the source or dest are not 2 byte aligned then everything must be
  653. |* done as byte copies.
  654. |*
  655.  
  656. gotArgs:
  657.     movl        a0,d0
  658.     orl        sp@(12),d0
  659.     andl    #1,d0
  660.     jne        3f
  661.  
  662. |*
  663. |* Do as many 64-byte copies as possible.
  664. |*
  665.  
  666. 1:
  667.     cmpl        #64,d1
  668.     jlt         2f
  669.     movl       a0@+, a1@+
  670.     movl       a0@+, a1@+
  671.     movl       a0@+, a1@+
  672.     movl       a0@+, a1@+
  673.     movl       a0@+, a1@+
  674.     movl       a0@+, a1@+
  675.     movl       a0@+, a1@+
  676.     movl       a0@+, a1@+
  677.     movl       a0@+, a1@+
  678.     movl       a0@+, a1@+
  679.     movl       a0@+, a1@+
  680.     movl       a0@+, a1@+
  681.     movl       a0@+, a1@+
  682.     movl       a0@+, a1@+
  683.     movl       a0@+, a1@+
  684.     movl       a0@+, a1@+
  685.     subl       #64,d1
  686.     jra         1b
  687.  
  688. |*
  689. |* Copy up to 64 bytes of remainder, in 4-byte chunks.  Do this quickly
  690. |* by dispatching into the middle of a sequence of move instructions.
  691. |*
  692.  
  693. 2:
  694.     movl    d1,d0
  695.     andl    #3,d1
  696.     subl    d1,d0
  697.     asrl    #1,d0
  698.     negl    d0
  699.     jmp        pc@(34, d0:w)    
  700.     movl       a0@+, a1@+
  701.     movl       a0@+, a1@+
  702.     movl       a0@+, a1@+
  703.     movl       a0@+, a1@+
  704.     movl       a0@+, a1@+
  705.     movl       a0@+, a1@+
  706.     movl       a0@+, a1@+
  707.     movl       a0@+, a1@+
  708.     movl       a0@+, a1@+
  709.     movl       a0@+, a1@+
  710.     movl       a0@+, a1@+
  711.     movl       a0@+, a1@+
  712.     movl       a0@+, a1@+
  713.     movl       a0@+, a1@+
  714.     movl       a0@+, a1@+
  715.     movl       a0@+, a1@+
  716.  
  717. |*
  718. |* Do one byte copies until done.
  719. |*
  720.  
  721. 3:
  722.     tstl        d1
  723.     jle         4f
  724.     movb       a0@+,a1@+
  725.     subql       #1,d1
  726.     jra         3b
  727.  
  728. |* 
  729. |* Return.
  730. |*
  731.  
  732. 4: 
  733.     clrl    d0
  734.     rts
  735.  
  736. |* Vm_CopyOut is just like Vm_CopyIn except that it checks to make sure
  737. |* that the destination is in the user area (otherwise this would be a
  738. |* trap door to write to kernel space).
  739.  
  740.     .globl _Vm_CopyOut, _mach_FirstUserAddr, _mach_LastUserAddr
  741. _Vm_CopyOut:
  742.     movl    sp@(4),d1            | Get number of bytes into a
  743.                         |     register.
  744.     movl        sp@(8),a0            | Get source and dest addresses
  745.     movl        sp@(12),a1            |     into a register.
  746.     cmpl    _mach_FirstUserAddr,a1
  747.     jcs        5f
  748.     movl    a1,d0
  749.     subql    #1,d0
  750.     addl    d1,d0
  751.     jcs        5f
  752.     cmpl    _mach_LastUserAddr,d0
  753.     jls        gotArgs
  754.  
  755. |* User address out of range.  Check for a zero byte count before
  756. |* returning an error, though;  there appear to be kernel routines
  757. |* that call Vm_CopyOut with a zero count but bogus other arguments.
  758.  
  759. 5:
  760.     tstl    d1
  761.     jne        6f
  762.     clrl    d0
  763.     rts
  764. 6:
  765.     movl    #0x20000,d0
  766.     rts
  767.  
  768. |*
  769. |* ----------------------------------------------------------------------
  770. |*
  771. |* Vm_StringNCopy
  772. |*
  773. |*    Copy the NULL terminated string from *sourcePtr to *destPtr up
  774. |*    numBytes worth of bytes.
  775. |*
  776. |*    ReturnStatus
  777. |*    Vm_StringNCopy(numBytes, sourcePtr, destPtr, bytesCopiedPtr)
  778. |*        register int numBytes;      /* The number of bytes to copy */
  779. |*        Address sourcePtr;          /* Where to copy from. */
  780. |*        Address destPtr;            /* Where to copy to. */
  781. |*        int    *bytesCopiedPtr;    /* Number of bytes copied. */
  782. |*
  783. |*    NOTE: The trap handler assumes that this routine does not push anything
  784. |*          onto the stack.  It uses this fact to allow it to return to the
  785. |*          caller of this routine upon an address fault.  If you must push
  786. |*          something onto the stack then you had better go and modify 
  787. |*          "CallTrapHandler" in asmDefs.h appropriately.
  788. |*
  789. |* Results:
  790. |*    Normally returns SUCCESS.  If a non-recoverable bus error occurs,
  791. |*    then the trap handler fakes up a SYS_ARG_NO_ACCESS return from
  792. |*    this procedure.
  793. |*
  794. |* Side effects:
  795. |*    The area that destPtr points to is modified and *bytesCopiedPtr 
  796. |*    contains the number of bytes copied.
  797. |*
  798. |* ----------------------------------------------------------------------
  799. |*
  800.     .globl  _Vm_StringNCopy
  801. _Vm_StringNCopy:
  802.     movl        sp@(4),d1            | Get number of bytes into a
  803.                         |     register.
  804.     movl        sp@(8),a0            | Get source and dest addresses
  805.     movl        sp@(12),a1            |     into a register.
  806.  
  807. 1: 
  808.     movb    a0@, a1@+            | Copy the character.
  809.     cmpb    #0, a0@+            | See if hit null in string.
  810.     beq        2f
  811.     subl    #1, d1                | Decrement the byte counter.
  812.     bne        1b                | Copy more chars if haven't
  813.                         |     reached the limit.
  814. 2: 
  815.     movl    sp@(4), d0            | Compute the number of bytes
  816.     subl    d1, d0                |     copied and store the
  817.     movl    sp@(16), a0            |     result.
  818.     movl    d0, a0@
  819.     clrl    d0                | Return SUCCESS.
  820.     rts
  821.  
  822.  
  823. |*
  824. |* ----------------------------------------------------------------------
  825. |*
  826. |* Vm_TouchPages --
  827. |*
  828. |*    Touch the range of pages.
  829. |*
  830. |*    void
  831. |*    Vm_TouchPages(firstPage, numPages)
  832. |*        int    firstPage;    /* First page to touch. */
  833. |*        int    numPages;    /* Number of pages to touch. */
  834. |*
  835. |*    NOTE: The trap handler assumes that this routine does not push anything
  836. |*          onto the stack.  It uses this fact to allow it to return to the
  837. |*          caller of this routine upon an address fault.  If you must push
  838. |*          something onto the stack then you had better go and modify 
  839. |*          "CallTrapHandler" in asmDefs.h appropriately.
  840. |*
  841. |* Results:
  842. |*    Returns SUCCESS if were able to touch the page (which is almost
  843. |*    always).  If a bus error (other than a page fault) occurred while 
  844. |*    reading user memory, then SYS_ARG_NO_ACCESS is returned (this return
  845. |*    occurs from the trap handler, rather than from this procedure).
  846. |*
  847. |* Side effects:
  848. |*    None.
  849. |*
  850. |* ----------------------------------------------------------------------
  851. |*
  852.     .globl _Vm_TouchPages
  853. _Vm_TouchPages:
  854.     movl    sp@(4),d0    | d0 <= firstPage
  855.     movl    #VMMACH_PAGE_SHIFT, d1
  856.     asll    d1, d0        | d0 <= d0 << VMMACH_PAGE_SIZE
  857.     movl    d0, a0        | a0 <= Starting address    
  858.     movl    sp@(8), d0    | d0 <= numPages
  859. 1:
  860.     tstl    d0        | Quit when d0 == 0
  861.     jeq        2f
  862.     movl    a0@, d1        | Touch the page at the address in a0
  863.     subql    #1, d0        | Go back around to touch the next page.
  864.     addl    #VMMACH_PAGE_SIZE, a0
  865.     jra        1b
  866.  
  867. 2:
  868.     rts
  869.  
  870. |*
  871. |* The address marker below is there so that the trap handler knows the
  872. |* end of code that may take a page fault while copying into/out of
  873. |* user space.
  874.  
  875.     .globl _VmMachCopyEnd
  876. _VmMachCopyEnd:
  877.